package com.easy.common.utils;

import cn.hutool.core.collection.CollectionUtil;
import lombok.experimental.UtilityClass;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 生成的code码总长度为16位，将主键id转换为16进制，然后转换为字符数组后分别查到基数位置，1、3、5、7等共8个位置，
 * 数值截止位置已分隔符表示之前的为数据。后边的为随机码
 */
@UtilityClass
public class IdTransUtils {
    /**
     * 填充码
     */
    private static final char[] PADDING_CODE = new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
            'a', 'b', 'c', 'd', 'e', 'f', 'h',
            'i', 'j', 'l', 'm', 'n', 'o', 'p',
            'q', 'r', 's', 't', 'u', 'v', 'w'};
    /**
     * 区分数据截止到哪一位
     */
    private static final char[] SPLIT_CHAR = new char[]{'g', 'k', 'z', 'x', 'y'};
    /**
     * 加密对应关系
     */
    private static final Map<Character, Character> EN_MAP = new
            ConcurrentHashMap(16) {
                {
                    put('0', '7');
                    put('1', 'a');
                    put('2', '3');
                    put('3', 'c');
                    put('4', '0');
                    put('5', '9');
                    put('6', 'e');
                    put('7', '1');
                    put('8', '4');
                    put('9', '2');
                    put('a', '5');
                    put('b', 'f');
                    put('c', '6');
                    put('d', 'd');
                    put('e', '8');
                    put('f', 'b');
                }
            };
    /**
     * 解密对应关系
     */
    private static final Map<Character, Character> DE_MAP = new
            ConcurrentHashMap(16) {
                {
                    put('7', '0');
                    put('a', '1');
                    put('3', '2');
                    put('c', '3');
                    put('0', '4');
                    put('9', '5');
                    put('e', '6');
                    put('1', '7');
                    put('4', '8');
                    put('2', '9');
                    put('5', 'a');
                    put('f', 'b');
                    put('6', 'c');
                    put('d', 'd');
                    put('8', 'e');
                    put('b', 'f');
                }
            };
    /**
     * 加密后长度
     */
    private static final Integer CODE_LENGTH = 16;


    public static void main(String[] args) {
        /*List<String> enId = new ArrayList<>();
        for (int i = 1; i < 100; i++) {
            final String s = genBizCode(i);
            enId.add(s);
            System.out.println(s);
        }
        for (String s : enId) {
            final Integer integer = parseBizCode(s);
            System.out.println(integer);
        }*/
        System.out.println(genBizCode(2432));
        System.out.println(parseBizCode("721ardbgpaa3ces0"));
    }

    /**
     * 生成唯一code码
     *
     * @param dbUniq 对应业务数据库主键
     * @return 唯一编码
     */
    public static String genBizCode(Integer dbUniq) {
        List<Character> list = new ArrayList<>();
        //获取十六进制数据id
        String idHex = Integer.toHexString(dbUniq);
        //获取十六进制对应的字母数组
        char[] idHexCharArr = idHex.toCharArray();
        //标识是否完成数据填充
        boolean isDataFinish = false;
        //标识是否完成分隔数据填充
        boolean isPaddingSplitData = false;
        //数据下标
        int dIndex = 0;

        for (int i = 0; i < CODE_LENGTH; i++) {
            if (i % 2 == 0) {
                //偶数位填充随机数
                list.add(PADDING_CODE[randomInt(PADDING_CODE.length)]);
            } else {
                //判断数据部分是否填充完毕
                if (isDataFinish) {
                    //判断分隔数据是否填充完毕
                    if (!isPaddingSplitData) {
                        list.add(SPLIT_CHAR[randomInt(SPLIT_CHAR.length)]);
                        isPaddingSplitData = true;
                    } else {
                        list.add(PADDING_CODE[randomInt(PADDING_CODE.length)]);
                    }
                } else {
                    //奇数位填充正式数据
                    list.add(EN_MAP.get(idHexCharArr[dIndex++]));
                    if (dIndex == idHexCharArr.length) {
                        isDataFinish = true;
                    }
                }
            }
        }
        String join = CollectionUtil.join(list, "");
        return join.toLowerCase();
    }

    /**
     * 返回业务数据库对应唯一主键
     *
     * @return 数据库主键值
     */
    public static Integer parseBizCode(String bizCode) {
        final char[] chars = bizCode.toCharArray();
        List<Character> dataList = new ArrayList<>();
        boolean ifFinish = false;
        //循环加密串
        for (int i = 0; i < chars.length; i++) {
            //跳过偶数位填充信息
            if (i % 2 == 0) {
                continue;
            }
            //判断是否为结束符
            for (char c : SPLIT_CHAR) {
                if (c == chars[i]) {
                    ifFinish = true;
                    break;
                }
            }
            if (ifFinish) {
                break;
            }
            //获取并转换为真实数据
            dataList.add(DE_MAP.get(chars[i]));
        }
        //拼接成16进制
        String join = CollectionUtil.join(dataList, "");
        //解析成10进制id
        return Integer.parseInt(join, 16);
    }


    private static int randomInt(int exclude) {
        return getRandom().nextInt(exclude);
    }

    private static ThreadLocalRandom getRandom() {
        return ThreadLocalRandom.current();
    }

}
